"use strict";
import H from "../../parts/Globals.js";
import "../../parts/Utilities.js";

var Annotation = H.Annotation,
  CrookedLine = Annotation.types.crookedLine,
  ControlPoint = Annotation.ControlPoint,
  MockPoint = Annotation.MockPoint;

function getSecondCoordinate(p1, p2, x) {
  return ((p2.y - p1.y) / (p2.x - p1.x)) * (x - p1.x) + p1.y;
}

/**
 * @class
 * @extends Annotation.CrookedLine
 * @memberOf Annotation
 **/
function Tunnel() {
  CrookedLine.apply(this, arguments);
}

H.extendAnnotation(
  Tunnel,
  CrookedLine,
  /** @lends Annotation.Tunnel# */
  {
    getPointsOptions: function () {
      var pointsOptions = CrookedLine.prototype.getPointsOptions.call(this);

      pointsOptions[2] = this.heightPointOptions(pointsOptions[1]);
      pointsOptions[3] = this.heightPointOptions(pointsOptions[0]);

      return pointsOptions;
    },

    getControlPointsOptions: function () {
      return this.getPointsOptions().slice(0, 2);
    },

    heightPointOptions: function (pointOptions) {
      var heightPointOptions = H.merge(pointOptions);

      heightPointOptions.y += this.options.typeOptions.height;

      return heightPointOptions;
    },

    addControlPoints: function () {
      CrookedLine.prototype.addControlPoints.call(this);

      var options = this.options,
        controlPoint = new ControlPoint(
          this.chart,
          this,
          H.merge(
            options.controlPointOptions,
            options.typeOptions.heightControlPoint
          ),
          2
        );

      this.controlPoints.push(controlPoint);

      options.typeOptions.heightControlPoint = controlPoint.options;
    },

    addShapes: function () {
      this.addLine();
      this.addBackground();
    },

    addLine: function () {
      var line = this.initShape(
        H.merge(this.options.typeOptions.line, {
          type: "path",
          points: [
            this.points[0],
            this.points[1],
            function (target) {
              var pointOptions = MockPoint.pointToOptions(
                target.annotation.points[2]
              );

              pointOptions.command = "M";

              return pointOptions;
            },
            this.points[3],
          ],
        }),
        false
      );

      this.options.typeOptions.line = line.options;
    },

    addBackground: function () {
      var background = this.initShape(
        H.merge(this.options.typeOptions.background, {
          type: "path",
          points: this.points.slice(),
        })
      );

      this.options.typeOptions.background = background.options;
    },

    /**
     * Translate start or end ("left" or "right") side of the tunnel.
     *
     * @param {number} dx - the amount of x translation
     * @param {number} dy - the amount of y translation
     * @param {boolean} [end] - whether to translate start or end side
     */
    translateSide: function (dx, dy, end) {
      var topIndex = Number(end),
        bottomIndex = topIndex === 0 ? 3 : 2;

      this.translatePoint(dx, dy, topIndex);
      this.translatePoint(dx, dy, bottomIndex);
    },

    /**
     * Translate height of the tunnel.
     *
     * @param {number} dh - the amount of height translation
     */
    translateHeight: function (dh) {
      this.translatePoint(0, dh, 2);
      this.translatePoint(0, dh, 3);

      this.options.typeOptions.height = this.points[3].y - this.points[0].y;
    },
  },

  /**
   * A tunnel annotation.
   *
   * @extends annotations.crookedLine
   * @sample highcharts/annotations-advanced/tunnel/
   *         Tunnel
   * @product highstock
   * @optionparent annotations.tunnel
   */
  {
    typeOptions: {
      xAxis: 0,
      yAxis: 0,
      /**
       * Background options.
       *
       * @type {Object}
       * @excluding height, point, points, r, type, width, markerEnd,
       *            markerStart
       */
      background: {
        fill: "rgba(130, 170, 255, 0.4)",
        strokeWidth: 0,
      },
      line: {
        strokeWidth: 1,
      },
      /**
       * The height of the annotation in terms of yAxis.
       */
      height: -2,

      /**
       * Options for the control point which controls
       * the annotation's height.
       *
       * @extends annotations.crookedLine.controlPointOptions
       * @excluding positioner, events
       */
      heightControlPoint: {
        positioner: function (target) {
          var startXY = MockPoint.pointToPixels(target.points[2]),
            endXY = MockPoint.pointToPixels(target.points[3]),
            x = (startXY.x + endXY.x) / 2;

          return {
            x: x - this.graphic.width / 2,
            y: getSecondCoordinate(startXY, endXY, x) - this.graphic.height / 2,
          };
        },
        events: {
          drag: function (e, target) {
            if (
              target.chart.isInsidePlot(
                e.chartX - target.chart.plotLeft,
                e.chartY - target.chart.plotTop
              )
            ) {
              target.translateHeight(this.mouseMoveToTranslation(e).y);

              target.redraw(false);
            }
          },
        },
      },
    },

    /**
     * @extends annotations.crookedLine.controlPointOptions
     * @excluding positioner, events
     */
    controlPointOptions: {
      events: {
        drag: function (e, target) {
          if (
            target.chart.isInsidePlot(
              e.chartX - target.chart.plotLeft,
              e.chartY - target.chart.plotTop
            )
          ) {
            var translation = this.mouseMoveToTranslation(e);

            target.translateSide(translation.x, translation.y, this.index);

            target.redraw(false);
          }
        },
      },
    },
  }
);

Annotation.types.tunnel = Tunnel;

export default Tunnel;
